//
//  SKLRC4.m
//  sigleAPP
//
//  Created by SKL on 2017/11/14.
//  Copyright © 2017年 SKL. All rights reserved.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

/*
 * 将字符转换为数值
 * */
int c2i(char ch)
{
    // 如果是数字，则用数字的ASCII码减去48, 如果ch = '2' ,则 '2' - 48 = 2
    if(isdigit(ch))
        return ch - 48;
    
    // 如果是字母，但不是A~F,a~f则返回
    if( ch < 'A' || (ch > 'F' && ch < 'a') || ch > 'z' )
        return -1;
    
    // 如果是大写字母，则用数字的ASCII码减去55, 如果ch = 'A' ,则 'A' - 55 = 10
    // 如果是小写字母，则用数字的ASCII码减去87, 如果ch = 'a' ,则 'a' - 87 = 10
    if(isalpha(ch))
        return isupper(ch) ? ch - 55 : ch - 87;
    
    return -1;
}

/*
 * 功能：将十六进制字符串转换为整型(int)数值
 * */
int hex2dec(char *hex)
{
    int len;
    int num = 0;
    int temp;
    int bits;
    int i;
    
    // 此例中 hex = "1de" 长度为3, hex是main函数传递的
    len = (int)strlen(hex);
    
    for (i=0, temp=0; i<len; i++, temp=0)
    {
        // 第一次：i=0, *(hex + i) = *(hex + 0) = '1', 即temp = 1
        // 第二次：i=1, *(hex + i) = *(hex + 1) = 'd', 即temp = 13
        // 第三次：i=2, *(hex + i) = *(hex + 2) = 'd', 即temp = 14
        temp = c2i( *(hex + i) );
        // 总共3位，一个16进制位用 4 bit保存
        // 第一次：'1'为最高位，所以temp左移 (len - i -1) * 4 = 2 * 4 = 8 位
        // 第二次：'d'为次高位，所以temp左移 (len - i -1) * 4 = 1 * 4 = 4 位
        // 第三次：'e'为最低位，所以temp左移 (len - i -1) * 4 = 0 * 4 = 0 位
        bits = (len - i - 1) * 4;
        temp = temp << bits;
        
        // 此处也可以用 num += temp;进行累加
        num = num | temp;
    }
    
    // 返回结果
    return num;
}

#define SBOX_LEN 256

unsigned char sbox[SBOX_LEN];
unsigned char kbox[SBOX_LEN];


/*
 * 在初始化的过程中，密钥的主要功能是将S-box搅乱，i确保S-box的
 * 每个元素都得到处理，j保证S-box的搅乱是随机的。而不同的S-box
 * 在经过伪随机子密码生成算法的处理后可以得到不同的子密钥序列，
 * 并且，该序列是随机的：
 */
void init_sbox(void)
{
    int i, j = 0;
    unsigned char tmp;
    
    for (i = 0; i < SBOX_LEN; i++)
        sbox[i] = i;
    
    for (i = 0; i < SBOX_LEN; i++)
    {
        j = (j + sbox[i] + kbox[i]) % SBOX_LEN;
        tmp = sbox[i];
        sbox[i] = sbox[j];
        sbox[j] = tmp;
    }
}

void init_kbox(unsigned char key[],int key_len)
{
    int i = 0;
    
    /*
     * 由于密钥串的长度较短，所以在初始化时是循环利用的。
     */
    for (i = 0; i < SBOX_LEN; i++)
        kbox[i] = key[i % key_len];
}

void rc4_encrypt(unsigned char *data, unsigned char *buf, int len)
{
    int i = 0, j = 0, t, index = 0;
    unsigned char tmp;
    
    if (data == NULL || buf == NULL || len <= 0)
        return;
    
    while (index < len)
    {
        /*
         * 产生一个字节随机数的方法：
         * i = (i + 1) MOD 256
         * j = (j + Si) MOD 256
         * Swap Si and Sj
         * t = (Si + Sj) MOD 256
         * K = St
         */
        i = (i + 1) % SBOX_LEN;
        j = (j + sbox[i]) % SBOX_LEN;
        tmp = sbox[i];
        sbox[i] = sbox[j];
        sbox[j] = tmp;
        t = (sbox[i] + sbox[j]) % SBOX_LEN;
        
        buf[index] = data[index] ^ sbox[t]; //异或运算
        index++;
    }
}

void rc4_decrypt(unsigned char *cryptdata, unsigned char *key,unsigned char *data)
{
    int key_len = (int)strlen((char*)key);
    int data_len= (int)strlen((char*)cryptdata)/2;
    unsigned char data_en[data_len];
    //printf("解密前key_len：%d ，data_len：%d \n",key_len,data_len);
    
    init_kbox(key,key_len);
    init_sbox();
    
    for (int i = 0; i < data_len; i++){
        char ch[3]={0};
        ch[0] =cryptdata[2*i];
        ch[1] =cryptdata[2*i+1];
        data_en[i] = hex2dec(ch);
    }
    
    rc4_encrypt(data_en, data, data_len);
}


